const url = require("url");
const Layer = require("./layer");
const Route = require("./route");
const methods = require("methods");
function Router() {
  let router = function (req, res, next) {
    // 等会中间件匹配到后 会执行此方法
    router.handle(req, res, next);
  };
  router.stack = [];
  router.__proto__ = proto;
  return router;
}
const proto = {};
methods.forEach((method) => {
  proto[method] = function (path, handlers) {
    if (!Array.isArray(handlers)) {
      // 我们创建的二级路由调用了 router.get()
      handlers = Array.from(arguments).slice(1);
    }

    const route = new Route();
    const layer = new Layer(path, route.dispatch.bind(route));

    layer.route = route; // 当调用路由方法时，会产生一个route

    this.stack.push(layer);
    route[method](handlers); // 让里层的route 记住用户的方法
  };
});
proto.use = function (path, ...handlers) {
  if (typeof path !== "string") {
    // path 就是路径
    handlers.unshift(path); // 这里用户没有写路径
    path = "/";
  }
  handlers.forEach((handler) => {
    let layer = new Layer(path, handler);
    layer.route = undefined;
    this.stack.push(layer); // 将layer 放到stack中
  });
};
proto.handle = function (req, res, out) {
  let { pathname } = url.parse(req.url);
  let idx = 0;
  let removed = ""; // 记录进入到中间件的时候 删除掉
  const next = (err) => {
    if (idx >= this.stack.length) return out(); // 递归的终止条件
    let layer = this.stack[idx++];
    if (removed) {
      // 在从中间件出来的时候 要加回删除的内容
      req.url = removed + req.url;
      removed = "";
    }
    if (err) {
      if (!layer.route) {
        layer.handle_error(err, req, res, next);
      } else {
        next(err); // 如果是路由，需要继续向下执行
      }
    } else {
      if (layer.match(pathname)) {
        // layer.params
        req.params = layer.params || {};
        if (!layer.route) {
          if (layer.handler.length !== 4) {
            // 正常情况下 不走错误处理中间件

            if (layer.path !== "/") {
              removed = layer.path;
              req.url = req.url.slice(removed.length); // 移除中间件的路径
            }

            layer.handle_request(req, res, next);
          } else {
            next();
          }
        } else {
          // route.dispatch
          // 在看这个layer 对应的route 上面的methods  是否包含当前请求的methods
          if (layer.route.methods[req.method.toLowerCase()]) {
            layer.handle_request(req, res, next);
          } else {
            next();
          }
        }
      } else {
        next();
      }
    }
  };
  next();
};

module.exports = Router;

// 1.路由就是匹配路径以及方法的，都满足才执行
